package com.atguigu.exam.service.impl;


import com.atguigu.exam.entity.ExamRecord;
import com.atguigu.exam.entity.Paper;
import com.atguigu.exam.entity.PaperQuestion;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.exception.ExamException;
import com.atguigu.exam.mapper.PaperMapper;
import com.atguigu.exam.mapper.PaperQuestionMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.ExamRecordService;
import com.atguigu.exam.service.PaperQuestionService;
import com.atguigu.exam.service.PaperService;
import com.atguigu.exam.vo.AiPaperVo;
import com.atguigu.exam.vo.PaperVo;
import com.atguigu.exam.vo.RuleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 试卷服务实现类
 */
@Slf4j
@Service
public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> implements PaperService {
    @Autowired
    private QuestionMapper questionMapper;
    @Autowired
    private PaperQuestionMapper paperQuestionMapper;
    @Autowired
    private PaperQuestionService paperQuestionService;
    @Autowired
    private ExamRecordService examRecordService;


    @Override
    public Paper getPaperById(Long id) {
        Paper paper = baseMapper.selectById(id);
        List<Question> questions = questionMapper.getPaperQuestionById(paper.getId());
        paper.setQuestions(questions);
        return paper;

    }

    @Override
    public Paper createPaper(PaperVo paperVo) {
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, paperVo.getName()));
        if (exists) {
            throw new ExamException(250, "该试卷已存在");
        }
        Paper paper = new Paper();
        BeanUtils.copyProperties(paperVo,paper);
        paper.setStatus("DRAFT");
        Map<Long, BigDecimal> questions = paperVo.getQuestions();
        paper.setQuestionCount(questions.size());
        BigDecimal totalScore = questions.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        paper.setTotalScore(totalScore);
        baseMapper.insert(paper);
        List<PaperQuestion> paperQuestions = questions.entrySet().stream().map(entry -> new PaperQuestion(paper.getId(), entry.getKey(), entry.getValue())).collect(Collectors.toList());
        paperQuestionService.saveBatch(paperQuestions);
        return paper;
    }

    @Override
    public Paper updatePaper(Integer id, PaperVo paperVo) {
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, paperVo.getName()).ne(Paper::getId,id));
        if (exists) {
            throw new ExamException(250, "该试卷已存在");
        }
        Paper paper = baseMapper.selectById(id);
        if ("PUBLISHED".equals(paper.getStatus())) {
            throw new ExamException(250, "该试卷已发布，不能修改");
        }
        BeanUtils.copyProperties(paperVo,paper);
        paperQuestionMapper.delete(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, id));
        paper.setUpdateTime(new Date());
        Map<Long, BigDecimal> questions = paperVo.getQuestions();
        paper.setQuestionCount(questions.size());
        BigDecimal totalScore = questions.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        paper.setTotalScore(totalScore);
        baseMapper.updateById(paper);
        List<PaperQuestion> paperQuestions = questions.entrySet().stream().map(entry -> new PaperQuestion(paper.getId(), entry.getKey(), entry.getValue())).collect(Collectors.toList());
        paperQuestionService.saveBatch(paperQuestions);
        return paper;
    }

    @Override
    public void updatePaperStatus(Integer id, String status) {
        long count = examRecordService.count(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getExamId, id).eq(ExamRecord::getStatus,"进行中"));
        if (count > 0) {
            throw new ExamException(250, "该试卷已经进行了考试，不能更新状态");
        }
        baseMapper.update(null, new LambdaUpdateWrapper<Paper>().eq(Paper::getId, id).set(Paper::getStatus, status));
    }

    @Override
    public void deletePaper(Integer id) {
        long count = examRecordService.count(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getExamId, id).eq(ExamRecord::getStatus,"进行中"));
        if (count > 0) {
            throw new ExamException(250, "该试卷已经进行了考试，不能删除");
        }
        paperQuestionMapper.delete(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, id));
        baseMapper.deleteById(id);
    }

    @Override
    public Paper createPaperWithAI(AiPaperVo aiPaperVo) {
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, aiPaperVo.getName()));
        if (exists) {
            throw new ExamException(250, "该试卷已存在");
        }
        Paper paper = new Paper();
        BeanUtils.copyProperties(aiPaperVo,paper);
        paper.setStatus("DRAFT");
        baseMapper.insert(paper);
        List<RuleVo> ruleVos = aiPaperVo.getRules();
        BigDecimal totalScore = BigDecimal.ZERO;
        Integer questionCount = 0;
        for (RuleVo ruleVo : ruleVos) {
            if (ruleVo.getCount() <= 0) {
                continue;
            }
            List<Question> questions = questionMapper.selectList(new LambdaQueryWrapper<Question>().eq(Question::getType, ruleVo.getType().name())
                    .in(Question::getCategoryId, ruleVo.getCategoryIds()));
            int count = 0;
            if (questions.size() < ruleVo.getCount()) {
                questionCount += questions.size();
                count = questions.size();
            }else {
                questionCount += ruleVo.getCount();
                count = ruleVo.getCount();
            }
            totalScore = totalScore.add(BigDecimal.valueOf((long) count * ruleVo.getScore()));
            Collections.shuffle(questions);
            List<Question> realQuestionList = questions.subList(0, count);
            List<PaperQuestion> paperQuestions = realQuestionList.stream().map(question ->
                    new PaperQuestion(paper.getId(), question.getId(), BigDecimal.valueOf(ruleVo.getScore()))
            ).collect(Collectors.toList());
            paperQuestionService.saveBatch(paperQuestions);
        }
        paper.setQuestionCount(questionCount);
        paper.setTotalScore(totalScore);
        baseMapper.updateById(paper);
        return paper;
    }
}